#!/usr/bin/python
# -*- coding: utf-8 -*-

import time, redis, datetime, json, pymongo, hashlib, random, os, sys

sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from exchange.utils.uuid import uuid
from exchange.com.db import db



ds = {}



#
# 撮合交易服务重启后需要从 mongodb 中提取最后的挂单状态 load 到内存中
#
def reload():

    print("reloading...")

    for symbol in db.get_symbols():
        db.process_orders_for_cancel(symbol)

        # 读取 orders 数据 加载到 内存中
        for o in db.get_orders(symbol):
            account, action, price, amount, seqno = o.get("account"), o.get("action"), o.get("price"), o.get("amount"), o.get("seqno")
            if symbol not in ds:
                ds[symbol] = { "buy": [], "sell": [] }
            # 插入到交易队列
            index = 0
            for x in ds[symbol][action]:
                if (price > x[2] and action == 'buy') or (price < x[2] and action == 'sell'):
                    break
                index += 1
            ds[symbol][action].insert(index, [seqno, account, price, amount, amount])

    print("reload finished.")



#
# 撤单处理
#
def match_for_cancel(queue):
    account, symbol, action, seqno = queue
    price, amount = 0.0, 0.0
    for x in ds[symbol][action]:
        if x[0] == seqno and x[1] == account:
            price, amount = x[2], x[4]
            ds[symbol][action].remove(x)
            continue
    if amount > 0.0:
        db.add_history_for_cancel( account, symbol, action, seqno, price, amount )


#
# 撮合抵消
#
def match_for_order(queue):
    account, symbol, action, price, amount = queue
    price = float(price)
    amount = float(amount)
    seqno = uuid.get_uuid(account + symbol + action)

    if action == 'buy' and price == 0.0:
        return

    if symbol not in ds:
        ds[symbol] = { "buy": [], "sell": [] }

    # 插入到交易队列
    index = 0
    for x in ds[symbol][action]:
        if (price > x[2] and action == 'buy') or (price < x[2] and action == 'sell'):
            break
        index += 1
    ds[symbol][action].insert(index, [seqno, account, price, amount, amount])

    db.add_order(account, symbol, action, price, amount)

    buys    = ds[symbol]['buy']
    sells   = ds[symbol]['sell']

    # 撮合抵消
    while 1:

        if len(buys) == 0 or len(sells) == 0:
            break

        buy_price   = buys [0][2]
        sell_price  = sells[0][2]

        if buy_price < sell_price:
            break

        deal_price  = sell_price if action == 'buy' else buy_price
        deal_amount = min(buys[0][4], sells[0][4])

        buys [0][4] -= deal_amount
        sells[0][4] -= deal_amount

        buyer, seller, buy_seqno, sell_seqno = buys[0][1], sells[0][1], buys[0][0], sells[0][0]

        db.add_history_for_deal(symbol, buyer, seller, buy_seqno, sell_seqno, deal_price, deal_amount)

        # 释放已经完成撮合的空单
        for k in ['buy', 'sell']:
            if ds[symbol][k][0][4] == 0.00:
                ds[symbol][k].pop(0)

#
# 撮合交易
#
def match():

    print("match servcie is started.")

    while 1:

        q = db.rdb.rpop("queue")
        if not q:
            time.sleep(0.1)
            continue

        queue = q.split(",")

        # 撤单处理
        if queue[0] == "cancel":
            match_for_cancel(queue[1:])
            continue

        # 下单处理
        if queue[0] == "order":
            match_for_order(queue[1:])
            continue



if __name__ == '__main__':
    reload()
    match()
